iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 6
0
Modern Web

從技術文章深入學習 JavaScript系列 第 6

Day 06 [this 02] ES6箭頭函數、箭頭函數與普通函數的區別

  • 分享至 

  • xImage
  •  

文章選自

作者:长安曹公子

連接:https://juejin.im/post/6844903805960585224

來源:掘金

基本知識

  1. 比一般定義函數還簡潔

    // 箭頭
    let foo = (bar, baz) => {
      console.log(bar);
      return bar
    }
    // 一般
    let foo = function(bar, baz) {
        console.log(bar)
        return bar
    }
    
  2. 一些更簡潔的寫法

    // 變量只有一個可以不用括號
    let foo = bar => {
        return bar
    }
    // 如果只有一行回傳值可以不用中括號(跟上面意思一樣)
    let foo = bar => bar 
    
    // 如果返回的是一個對象外面要括號(很少這樣寫)
    let foo = bar => ({id: bar, name: 'Mike'})
    // 等價於這樣
    let foo = bar => {
        return {
            id: bar,
            name: 'Mike'
        }
    }
    
    // 如果只有一行代碼然後要執行函數可以加void
    let foo = () => void bar();
    
    

不會創造this

箭頭函數只會繼承上一層this,意思是他會去找定義時的外層執行環境的this,因此箭頭函數的this的this在定義時就被決定,不會再有更改

例子一

var foo = 'global'

let fun1 = function () {
  setTimeout(() => {
    console.log(this.foo) // 指向fun1函數體的this(看下下行)
  }, 1000);
  // 比方說這裡
  console.log(this) 
}
let fun2 = function () {
  setTimeout(function () {
    console.log(this.foo);
  }, 1000);
}

fun1.call({foo: 'obj'})
fun2.call({foo: 'obj'})

https://ithelp.ithome.com.tw/upload/images/20200916/20124350VKCBlXSKxq.png

解析:

我們透過call把對象綁定到fun1以及fun2的tihs

  1. fun1裡面的setTimeout是利用箭頭函數定義,所以會指向fun1的this,因此打印出來綁定對象的foo即是obj

  2. fun2裡面的setTimeout是利用普通函數定義,所以會指向最後調用的對象,雖然我們把對象綁定到fun2上,可是最後執行的其實是window(因為setTimeout)

喔看起來已經相當清楚了呢~我們繼續來看下去

例子二

var id = 'global'
obj = {
  id: 'foo',
  test: () => {
    console.log(this.id)
  }
}

obj.test() // global

解析:

很明顯,假設是一般函數打印出來會是global,因為this會指向最後調用的對象

但這題會打印出函數定義時候會指向定義時的環境this,所以會指向window

這裡要注意,定義對象的大括號{}是無法形成一個單獨的執行環境的,它依舊是處於全局執行環境中!!

例子三

這一題證明了會指向外層的this

function foo() {
  let _this = this // 透過變量儲存this
  let bar = () => {
    console.log(this == _this)
  }
  bar()
}

foo() 

https://ithelp.ithome.com.tw/upload/images/20200916/20124350VHaHdB0Y3N.png

不能被call,apply,bind改變this指向

因為在定義時箭頭函數的this已經被定義,因此假如我們想要改變箭頭函數的this其實應該要改變外層的this指向

例子一

證明不能直接改變

let foo = function () {
  console.log(this);
}

let baz = () => {
  console.log(this); // 肯定指向window對象
}

foo.call({bar: 'bar'})
baz.call({bar: 'bar'})

https://ithelp.ithome.com.tw/upload/images/20200916/20124350iwgTFdiZy3.png

例子二

透過改變外層,其實就是 (不會創造this的例子一)

var id = 'global'
let bar = function () {
  let obj = {
    id: 'foo',
    test: () => {
      console.log(this.id);
    }
  }
  return obj.test  
}

let bazCall = bar.call({id: 'bazCall'})
bazCall()

https://ithelp.ithome.com.tw/upload/images/20200916/20124350GymkU5KnHJ.png

解析:

其實不難啦

就是要改變bar的this,因為test函數的this永遠指向bar的this

// 綁定對象給bar
let bazCall = bar.call({id: 'bazCall'})

bazCall()

不能當構造函數

let Foo = (bar, age) => {
  this.bar = bar;
  this.age = age;
};

let instance = new Foo ('Mike', 15);

https://ithelp.ithome.com.tw/upload/images/20200916/201243501hjFngWHGS.png

沒有prototype

let foo = () => {

};
console.log(foo.prototype);

https://ithelp.ithome.com.tw/upload/images/20200916/20124350xGzuoLK4h0.png

沒有arguments

例子一

一般函數會顯示所有參數

let foo = function (bar1, bar2) {
  console.log(bar1);
  console.log(bar2);

  console.log(arguments);
}
foo(123, 456)

https://ithelp.ithome.com.tw/upload/images/20200916/20124350Rs2BMlN3pA.png

箭頭函數:

let foo = (bar) => {
  console.log(bar);
  // 報錯,因為window沒有arguments對象
  console.log(arguments);
}
foo(123)

https://ithelp.ithome.com.tw/upload/images/20200916/20124350PCFubRbtB4.png

例子二

這題簡單來說還是證明箭頭函數會繼承外圍環境的this

function outer(val1, val2) {
  let argOut = arguments;
  console.log(argOut);    
  let fun = () => {
    let argIn = arguments;
    console.log(argIn);     
    console.log(argOut === argIn);  
  };
  fun();
}
outer(111, 222);

https://ithelp.ithome.com.tw/upload/images/20200916/20124350JoiMCAxne2.png

最關鍵的代碼是這裡

// let argOut = arguments;
let fun = () => {
    // 這裡的arguments其實是繼承自外圍
    // 也就是 let argOut = arguments 的 arguments
    let argIn = arguments;
    console.log(argIn);     
    console.log(argOut === argIn);  
};

上一篇
Day 05 [this 01] this、apply、call、bind
下一篇
Day 07 [原型鍊03] JavaScript中,new操作符的工作原理是什么
系列文
從技術文章深入學習 JavaScript29
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言